package com.beta.service.impl;

import com.baomidou.framework.service.impl.SuperServiceImpl;
import com.baomidou.mybatisplus.plugins.Page;
import com.beta.dto.Shipment.ShipmentsDetailDto;
import com.beta.dto.Shipment.ShipmentsDto;
import com.beta.em.order.OrderMode;
import com.beta.em.order.OrderStatus;
import com.beta.em.order.ShipmentStatus;
import com.beta.entity.Orders;
import com.beta.entity.Shipments;
import com.beta.event.order.OrderEvent;
import com.beta.event.order.OrderPayloadEvent;
import com.beta.mapper.OrderItemsMapper;
import com.beta.mapper.ShipmentsMapper;
import com.beta.service.*;
import com.beta.util.RandomUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * Shipments 表数据服务层接口实现类
 */
@Service
public class ShipmentsService extends SuperServiceImpl<ShipmentsMapper, Shipments> implements IShipmentsService {

    @Autowired
    private IPushToAppService pushToAppService;
    @Autowired
    private OrderItemsMapper orderItemsMapper;
    @Autowired
    private IDateTimeService dateTimeService;
    @Autowired
    private IOrdersService ordersService;
    @Autowired
    private IOrderStatusService orderStatusService;
    @Autowired
    private PublishService publishService;

    @Override
    public Shipments getShipmentByOrderId(Integer orderId) {
        if (Objects.isNull(orderId)) {
            throw new ServiceException("E40001");
        }
        return selectOne(new Shipments().setOrderId(orderId));
    }

    @Override
    public Page<ShipmentsDto> getShipments(Integer courierId, Page<ShipmentsDto> page, String status) {
        if(Objects.isNull(courierId)){
            throw new ServiceException("E00113");
        }
        List<ShipmentsDto> shipmentsDtos = baseMapper.getShipmentsByStatus(page, courierId, status);
        if(CollectionUtils.isEmpty(shipmentsDtos)){
            return page;
        }
        page.setRecords(shipmentsDtos);
        return page;
    }

    @Override
    public ShipmentsDetailDto getShipmentsDetail(Integer shipmentsId) {
        if(Objects.isNull(shipmentsId)) {
            throw new ServiceException("E50001");
        }
            ShipmentsDetailDto shipmentsDetailDto = baseMapper.getShipmentsOrderItem(shipmentsId);
            shipmentsDetailDto.setOrderItems(orderItemsMapper.getOrdersItems(Arrays.asList(shipmentsDetailDto.getOrderId())));
            return shipmentsDetailDto;
    }

    @Override
    public String generateShipmentCode() {
        DateFormat dateFormat = new SimpleDateFormat("yyMMdd");
        String yyMMdd = dateFormat.format(dateTimeService.toDbDate());
        String rand5String = RandomUtils.randomStringWithLength(5);
        return StringUtils.join(yyMMdd, rand5String);
    }

    @Override
    public Shipments executeCompleteByOrderId(Integer orderId) {
        Shipments whereEntity = new Shipments().setOrderId(orderId);
        Shipments shipments = selectOne(whereEntity);
        if (Objects.isNull(shipments)) {
            throw new ServiceException("E50001", shipments.getStatus());
        }
        if (ShipmentStatus.COMPLETED.getValue().equals(shipments.getStatus())) {
            return shipments;
        }
        if (!ShipmentStatus.SHIPPING.getValue().equals(shipments.getStatus())) {
            throw new ServiceException("E50002", shipments.getStatus());
        }

        Date dbDate = dateTimeService.toDbDate();
        Shipments updateEntity = new Shipments()
                .setId(shipments.getId())
                .setStatus(ShipmentStatus.COMPLETED.getValue())
                .setUpdatedAt(dbDate)
                .setCompletedAt(dbDate);
        updateSelectiveById(updateEntity);
        return selectById(shipments.getId());
    }


    public Shipments executeConfirmAssignment(Integer shipmentsId) {
        if (Objects.isNull(shipmentsId)) {
            throw new ServiceException("E50001");
        }
        Date dbDate = dateTimeService.toDbDate();
        Shipments updateEntity = new Shipments()
                .setId(shipmentsId)
                .setPickedAt(dbDate)
                .setUpdatedAt(dbDate)
                .setStatus(ShipmentStatus.PICKING.getValue());
        updateSelectiveById(updateEntity);

        Shipments shipments = selectById(shipmentsId);
        Orders orders = ordersService.selectById(shipments.getOrderId());

        // 发布订单已接单事件
        publishService.publishApplicationEvent(new OrderPayloadEvent(OrderEvent.PICKING, orders));

        return selectById(shipmentsId);
    }

    @Override
    public Shipments executeConfirmShip(Integer shipmentsId) {
        if (Objects.isNull(shipmentsId)) {
            throw new ServiceException("E50001");
        }
        Date dbDate = dateTimeService.toDbDate();
        Shipments updateEntity = new Shipments()
                .setId(shipmentsId)
                .setUpdatedAt(dbDate)
                .setShippedAt(dbDate)
                .setStatus(ShipmentStatus.SHIPPING.getValue());
        updateSelectiveById(updateEntity);
        Shipments shipmentsEntity = selectOne(new Shipments().setId(shipmentsId));
        Integer orderId = shipmentsEntity.getOrderId();
        orderStatusService.changeStatus(orderId, OrderStatus.DELIVERING, null);

        // 发布订单已接单事件
        publishService.publishApplicationEvent(new OrderPayloadEvent(OrderEvent.SHIPPING, ordersService.selectById(orderId)));

        return selectById(shipmentsId);
    }

    @Override
    public Shipments executeComplete(Integer shipmentsId) {
        if (Objects.isNull(shipmentsId)) {
            throw new ServiceException("E50001");
        }
        Integer orderId = selectById(shipmentsId).getOrderId();
        String orderMode = ordersService.selectById(orderId).getMode();
        Date dbDate = dateTimeService.toDbDate();

        if (OrderMode.CARTING.getValue().equals(orderMode)) {
            Orders updateEntity = new Orders().setId(orderId)
                    .setStatus(OrderStatus.CONFIRMED.getValue())
                    .setUpdatedAt(dbDate);
            ordersService.updateSelectiveById(updateEntity);
        }

        Orders updateOrderEntity = new Orders().setId(orderId).setUpdatedAt(dbDate).setStatus(OrderStatus.DELIVERING.getValue());
        ordersService.updateSelectiveById(updateOrderEntity);
        Integer userId = ordersService.selectOne(new Orders().setId(orderId)).getUserId();
        pushToAppService.pushToSingle(userId, "您的订单已发货", OrderStatus.DELIVERING.getValue());
        return selectById(shipmentsId);
    }

    @Override
    public Shipments executeReceiptConfirm(Integer shipmentsId) {
        if (Objects.isNull(shipmentsId)) {
            throw new ServiceException("shipments.invalid.id");
        }
        Integer orderId = selectById(shipmentsId).getOrderId();
        String orderMode = ordersService.selectById(orderId).getMode();
        if (OrderMode.CARTING.getValue().equals(orderMode)) {
            Orders updateEntity = new Orders().setId(orderId)
                    .setStatus(OrderStatus.CONFIRMED.getValue())
                    .setUpdatedAt(dateTimeService.toDbDate());
            ordersService.updateSelectiveById(updateEntity);
        }
        return selectById(shipmentsId);
    }

    @Override
    public Page<Shipments> getShipments(Page<Shipments> page,String code,Integer orderId,String courierName,String address) {
        List<Shipments> shipments = baseMapper.getShipments(page, code, orderId, courierName, address);
        for (Shipments shipment:shipments) {
            String cnValue = ShipmentStatus.getCnValue(shipment.getStatus());
            shipment.setStatus(cnValue);
        }
        page.setRecords(shipments);
        return page;
    }

    @Override
    public void updateShipmentsReceiver(Integer orderId,ShipmentsDto shipmentsDto) {
        if(Objects.isNull(orderId)){
            throw new ServiceException("shipments.invalid.orderId");
        }
        Shipments shipments = new Shipments().setReceiverAddress(shipmentsDto.getReceiverAddress())
                                             .setReceiverName(shipmentsDto.getReceiverName())
                                             .setReceiverPhone(shipmentsDto.getReceiverPhone())
                                             .setUpdatedAt(dateTimeService.toDbDate());
        updateSelective(shipments,new Shipments().setOrderId(orderId));
    }

}